从1到1100万用户的架构演变
你如何让系统从1个用户扩展到1100多万个用户?亚马逊网络服务(AWS)公司的解决方案架构师Joel Williams 在AWS re:Invent 2015大会上,就这个话题作了一场精彩的演讲:《扩展到你的头1000万个用户》。
如果你是资深AWS用户,那场演讲不适合你,但如果你刚接触AWS,刚接触云计算,或者无力跟上亚马逊不断推出的一大批新功能,这不失为一篇入门指南。
你可能也料到了,由于这是亚马逊人的演讲,亚马逊服务始终是解决任何问题的最主要办法。亚马逊的平台架构令人叹为观止,颇有启发性。从各部分彼此整合的情况来看,很显然,亚马逊在这方面做很到位:识别用户要求,然后确保拿出满足要求的产品。
一些值得关注的心得如下:
从SQL开始入手,只在确有必要时迁移到NoSQL。
一个一致的主题是,拿来组件后将它们分开来。这让那些组件可独立扩展,出现故障后不影响其他组件。这个原则适用于分解各层、构建微服务。
只致力于从事为贵公司带来差异化优势的任务,不做重复性工作。
可扩展性和冗余性不是两个独立的概念,这两方面常常可以同时做到。
AWS服务全球各地的12个地区
地区是指亚马逊有多个可用性区域(Availability Zones)的物理位置。地区范围覆盖:北美、南美、欧洲、中东、非洲和亚太。
可用性区域(AZ)通常是单单一个数据中心,不过它们可能由多个数据中心构成。
每个AZ彼此分得很开,各自有独立的电力和互联网连接。
AZ之间的唯一连接就是低延迟网络。比如说,两个AZ可能相隔5英里或15英里。低延迟网络的速度很快,快得应用程序运行起来如同所有AZ都在同一个数据中心。
每个地区有至少2个可用性区域。总共有32个AZ。
使用AZ,有可能为你的应用程序构建高可用性架构。
2016年会新增至少9个可用性区域和4个地区。
AWS在全球共有53个边缘位置
边缘位置被亚马逊的内容分发网络(CDN):CloudFront和亚马逊的托管DNS服务器:Route53使用。
边缘位置让用户能够访问内容,延迟非常低,不管用户在世界上的什么地方。
模块构建服务
AWS已构建了许多服务,这些服务在内部使用多个AZ,确保高可用性和高容错性。这里(https://aws.amazon.com/cn/about-aws/global-infrastructure/regional-product-services/)列出了在各地可使用什么样的服务(http://docs.aws.amazon.com/general/latest/gr/rande.html)。
你可以将这些服务用在你的应用程序中,要付费,没必要为自行确保高可用性而担心。
AZ里面存在一些服务:CloudFront、Route 53、S3、DynamoDB、弹性负载均衡(Elastic Load Balancing)、EFS、 Lambda、SQS、SNS、SES和SWF。
即便服务存在于单一AZ里面,也可以使用这些服务来构建高可用性架构。
在这种场景下,你只有1个用户,你想让网站运行起来。
你的架构看起来就像这样:
在单一实例(可能是类型t2.micro)上运行。实例类型包括:不同组合的处理器、内存、存储和网络资源,让你可以灵活地选择适合具体应用的资源组合。
单一实例将运行整个Web堆栈,比如说:Web应用程序、数据库和管理等。
使用亚马逊Route 53作为DNS服务器。
将单一的Elastic IP地址连接到该实例。
在一段时间里,运行顺畅。
纵向扩展
你需要更庞大的系统。最简单的扩展方法就是选择一个更大类型的实例。比如说,可能是c4.8xlarge或m3.2xlarge。
这种方法名为纵向扩展(vertical scaling)。
只要停止运行实例,选择一个新的实例类型,就可以运行起来,拥有更强的处理能力。
诸多组合的不同硬件配置可供选择。你可能拥有配备244GB内存的系统(2TB内存类型很快会推出),或者配备40个核心的系统。有High I/O实例、High CPU实例和High storage实例可供使用。
一些亚马逊服务随带Provisioned IOPS选项,以保证性能。其想法是,你可能为自己的服务使用比较小的实例类型,充分利用能提供可扩展服务的亚马逊服务(比如DynamoDB),那样你没必要操心。
纵向扩展有个大问题:没有故障切换机制,没有冗余性。如果实例有问题,你的网站就完蛋了。好比你的所有鸡蛋都放在一只篮子里。
最终,单一实例支持的规模很有限。你需要采取别的做法。
把单一主机分成多个主机:
一个主机用于网站。
一个主机用于数据库。运行你需要的任何数据库,但是你得负责数据库管理。
使用独立的主机让网站和数据库可以完全彼此独立扩展。比如说,也许数据库需要的机器比网站需要的来得庞大。
你可以使用数据库服务,而不是运行自己的数据库。
你是数据库管理员吗?你果真要想为备份操心吗?高可用性?补丁?操作系统?
使用服务的一大优点是,只要点击一下鼠标,就能设置好一套多可用性区域数据库。没必要为复制或任何这种事务操心。你的数据库将具有高可用性和高可靠性。
正如你所料,亚马逊在出售几种全面托管的数据库服务:
亚马逊RDS(关系数据库服务)。有好多选择:微软SQL Server、Oracle、MySQL、PostgreSQL、MariaDB和亚马逊Aurora。
亚马逊DynamoDB:一种NoSQL托管数据库。
亚马逊Redshift:PB级数据仓库系统。
亚马逊Aurora方面的详情:
存储容量可自动扩展至64TB。你再也不必为数据配置存储容量。
多达12个读取副本(read-replica)。
持续(增量)备份到S3。
横跨3个AZ的6路复制。这可以帮助你处理故障。
与MySQL兼容。
从SQL数据库开始入手,而不是NoSQL数据库。
建议从SQL数据库开始入手。
这项技术很成熟。
有许多的现成代码、社区、支持组织、图书和工具。
你的头1000万个用户不会搞坏SQL数据库。根本不会(除非你的数据很庞大)。
清晰的可扩展模式。
你什么时候需要从NoSQL数据库开始入手?
如果你在一年内需要存储超过5 TB的数据,或者面临数据超密集型的工作负载。
应用程序要求超低的延迟。
需要很高的吞吐量。你需要改动在读取和写入操作方面获得的输入/输出。
你没有任何关系数据。
使用单独的主机用于Web层。
将数据库存储在亚马逊RDS上。它会处理一切事务。
你要做的就这些。
设计架构时,你的应用程序就存在可用性问题。如果用于Web服务的主机出现故障,你的网站就瘫痪。
所以,你需要在另一个可用性区域的另一个Web实例。这没问题,因为AZ之间的延迟很低:只有几毫秒,就好像这些AZ几乎彼此相邻。
你还需要RDS的从属数据库在另一个AZ中运行。要是主数据库出了问题,应用程序就会自动切换到从属数据库。故障切换时没有必要更改应用程序,因为应用程序始终使用同一个端点。
弹性负载均衡器(ELB)被添加到配置中,在位于两个AZ的两个Web主机实例之间实现用户负载均衡。
弹性负载均衡器(ELB):
ELB是一种高可用性的托管负载均衡器。ELB存在于所有AZ中。它是面向你应用程序的单一DNS端点。只要把它放入到Route 53,它就会跨Web主机实例实现负载均衡。
ELB会进行健康检查(Health Checks),确保流量没有传送到出现故障的主机。
它能自动扩展,你啥都不用做。如果它看到额外流量,会在后台进行横向扩展和纵向扩展。你没必要管理它。你的应用程序扩展时,ELB也会随之扩展。
前一种配置在ELB后面有2个实例,实际上你可以在ELB后面有1000个实例。这是横向扩展。
你需要为数据库和RDS添加更多的读取副本。这将为写入主数据库卸掉负载。
将一部分流量移到别处,从而为你的Web层服务器减轻负载,从而提高性能和效率。将你Web应用程序中的静态内容转移到亚马逊S3和亚马逊CloudFront。CloudFront是亚马逊的CDN,负责将数据存储在全球各地的53个边缘位置。
亚马逊S3是一种基于对象的存储系统
它不像EBS,也不是连接到EC2实例的存储系统,它是一种对象存储系统,不是块存储系统。
它很适合存储静态内容,比如javascript、css、图像和视频。这种内容不需要放在EC2实例上。
高度耐用,可用性达到99.999999999%。
可无限扩展,你想添加多少数据就可以添加多少。客户将数PB数据存储在S3中。
支持最大为5TB的对象。
支持加密。你可以使用亚马逊的加密、你自己的加密技术或加密服务。
亚马逊CloudFront缓存你的内容。
它在边缘位置缓存内容,为用户提供延迟最低的访问服务。
没有CDN,用户访问内容时会遇到更高的延迟。服务器也会面临更高的负载,因为它们不仅要处理Web请求,还要提供内容。
一个客户需要以60 Gbps的速度提供内容。CloudFront处理一切,Web层甚至不知道发生了什么。
你还可以将会话状态从Web层转移出去,以此减轻负载。
将会话状态存储在ElastiCache或DynamoDB中。
这种方法还让系统可以在将来支持自动扩展。
你还可以将来自数据库的数据缓存到ElasticCache中,减轻负载。
你的数据库不需要处理所有的数据获取。缓存能处理许多这方面的工作,让数据库处理更重要的流量。
亚马逊DynamoDB:托管型NoSQL数据库
你配置所需的吞吐量。可以增加想要支付相应费用的读取和写入性能。
支持快速、稳定的性能。
完全分布式和容错。它存在于多个可用性区域中。
它是键值存储系统。支持JSON。
支持最大为400KB的文档。
亚马逊Elasticache:托管型Memcached或Redis
管理memcached集群并不让你赚更多钱,所以让亚马逊为你做这件事。这是亚马逊的营销口号。
集群自动为你扩展。它是自愈合基础设施,如果节点出现故障,就会自动启动新节点。
你还可以将动态内容转移到CloudFront,以此减轻负载。
许多人知道CloudFront能处理文件之类的静态内容,但它也能处理动态内容。这个话题在本演讲中没有作进一步探讨,不过这里有个链接(https://aws.amazon.com/cloudfront/dynamic-content/)。
自动扩展
如果你配置足够的容量,以便始终处理峰值流量负载(比如黑色星期五),无异于在浪费钱财。
更明智的是,让计算能力与需求相一致。这就是自动扩展(Auto Scaling)让你能做到的事,即自动调整计算集群的大小。
你可以定义资源池的最大值和最小值。用户得决定集群中最小数量的实例和最大数量的实例分别是多少。
CloudWatch是一种嵌入到所有应用中的管理服务。
CloudWatch事件驱动扩展。
想在处理器利用率方面进行扩展吗?想在延迟方面扩展吗?想在网络流量方面扩展吗?
你还可以将自己的自定义衡量指标纳入到CloudWatch中。如果你想在针对特定应用的方面进行扩展,可以把该衡量指标纳入到CloudWatch中,然后告诉自动扩展机制你想在该衡量指标方面进行扩展。
与前一个配置相比增添的是,自动扩展组添加到Web层。自动扩展组包括2个AZ,但可以扩展到3个AZ,不仅提供可扩展性,还提供可用性。
一个例子是在每个AZ中有3个Web层实例,但可以是数千个实例。你可以说想要最少10个实例,最多1000个实例。
ElastiCache用来卸载来自数据库的常见读取。
DynamoDB用来卸载会话数据。
你需要添加监控、衡量和日志机制。
主机层衡量指标。看一下自动扩展组里面的单一处理器实例,查清楚什么出了岔子。
总计衡量指标。看一下弹性负载均衡器上的衡量指标,了解整批实例的性能。
日志分析。使用CloudWatch日志,看一看应用程序告诉你了什么。CloudTrail可帮助你分析和管理日志。
外部站点性能。从最终用户的角度了解客户看到什么样的性能。使用New Relic或Pingdom之类的服务。
你要了解客户有什么样的评价。延迟很差劲?他们在访问网页时遇到了错误?
从你的配置获得尽量高的性能。自动扩展在这方面有所帮助。你不希望系统的处理器利用率只有20%。
自动化
基础设施变得庞大,它可以扩展到上千个实例。我们有读取副本,有横向扩展,但需要某种自动化工具来帮助管理这一切,我们可不想管理每一个实例。
自动化工具有层次结构:
自己动手:亚马逊 EC2和AWS CloudFormation。
更高层服务:AWS Elastic Beanstalk和AWS OpsWorks
AWS Elastic Beanstalk:为你的应用程序自动管理基础设施。它使用方便,但没有太多的控制。
AWS OpsWorks:这是一种种环境,你可以在其中构建层次化的应用程序,可使用Chef配方(recipe)来管理应用程序的层次。
另外启用进行持续集成和持续部署的功能。
AWS CloudFormation:历史最久。
提供最大的灵活性,因为它为你的堆栈提供了模板化视图。它可以用来构建你的整个堆栈,或者只构建堆栈的部分。
如果你想更新堆栈,只要更新Cloud Formation模板,它会更新你应用程序的某一个部分。
很大的控制度,但不太方便。
AWS CodeDeploy:将代码部署到一批EC2实例。
可部署到1个或上千个实例。
Code Deploy可指向自动扩展配置,那样代码可以部署到一组实例。
还可以与Chef和Puppet结合使用。
解耦/分离基础设施
使用SOA/微服务。从你的诸层拿来组件后,把它们分开来。比如将Web层与数据库层分开来时,构建独立的服务。
单个服务随后可以独立扩展。这为你在扩展方面提供了极大的灵活性,还有高可用性。
SOA是亚马逊构建的架构的一个重要部分。
松散耦合(Loose coupling)彻底解放了你。
可以让组件独立扩展,出现故障后不影响其他组件。
如果某个worker节点没有从SQS获取work,这严重吗?没啥关系,只要启动另一个节点。难免会出现故障,不妨构建一种可处理故障的架构。
将一切设计为黑盒子。
解耦/分离交互关系。
偏爱内置冗余性和可扩展性的服务,而不是构建自己的服务。
不做重复性工作
只致力于从事为贵公司带来差异化优势的任务。
亚马逊有许多服务天生具有容错性,因为它们横跨多个AZ。比如说:队列、电子邮件、转码、搜索、数据库、监控、衡量、日志和计算。你没必要自行构建这些服务。
SQS:队列服务。
提供的第一种亚马逊服务。
它横跨多个AZ,所以具有容错性。
它具有可扩展、安全又简单等优点。
队列可帮助你在基础设施的不同部分之间传输消息,从而帮助基础设施。
以照片内容管理系统(CMS)为例。收集并处理照片的系统应该是两个不同的系统。它们应该能够独立扩展。它们应该松散耦合。获取照片后放入到队列中,worker就能从队列中获取照片,并进行相应处理。
AWS Lambda:让你不用配置或管理服务器,就可以运行代码。
让你可以解耦/分离应用程序的出色工具。
在照片CMS这个例子中,Lambda可以响应S3事件,那样S3文件添加后,Lam
bda的处理功能就自动被触发。
我们丢弃了EC2。它可以为你向外扩展,没有操作系统要管理。
获得超过100万个用户需要所有上述几点:
多个AZ
层与层之间的弹性负载均衡。不仅仅在Web层上,还要在应用层、数据层及拥有的其他任何层上。
自动扩展
面向服务的架构(SOA)
使用S3和CloudFront,智能化提供内容
把缓存放在数据库前面
从Web层移走状态
使用亚马逊SES发送电子邮件。
使用CloudWatch来监控。
随着规模变得更大,我们会在数据层遇到问题。你可能会开始遇到数据库方面的问题:与负责写入的主数据库争夺资源,这基本上意味着你向一台服务器发送的写入流量很有限。
你如何解决这个问题?
联合(federation)
切分(sharding)
把某种功能移到其他类型的数据库(NoSQL和图形数据库等)
联合:根据功能分成多个数据库
比如说,构建论坛数据库、用户数据库和产品数据库。之前你可能把这些功能统统都放在一个数据库中,现在将它们分开来。
不同的数据库可以彼此独立扩展。
缺点:你无法执行跨数据库查询;这就引出了下一个策略:切分。
切分-横跨多个主机来分割一个数据集
应用层更为复杂,但可扩展性方面实际上没有限制。
比如说,在用户数据库中,三分之一的用户可能被派到一个分片,三分之一被派到另一个分片,剩下三分之一被派到另一个分片。
将某种功能移到其他类型的数据库
开始考虑NoSQL数据库
如果你的数据不需要复杂的合并,比如说选手积分榜、快速获取点击流/日志数据、临时数据、热表、元数据/查询表,那么可以考虑改用NoSQL数据库。
这意味着,它们可以彼此独立地扩展。
扩展是个迭代过程。你规模变大后,总是能够做更多的事情。
对应用程序进行微调。
用更多的SOA来处理特性/功能。
从多AZ进入到多地区。
开始构建自定义解决方案,以解决你面临的、别人之前没有遇到过的特定问题。如果你需要服务于10亿个客户,就需要自定义解决方案。
深入分析整个堆栈。
回顾
使用多AZ基础设施来确保可靠性。
充分利用自扩展服务,比如ELB、S3、SQS、SNS和DynamoDB等。
在每个层面融入可靠性。可扩展性和冗余性不是两个独立的概念,这两方面常常可以同时实现。
从传统的关系SQL数据库开始入手。
基础设施内外的数据都要缓存。
在基础设施中使用自动化工具。
确保已落实了良好的衡量/监控/日志机制。确保弄清楚客户从你的应用程序得到什么样的体验。
将诸层分成单个服务(SOA),那样它们就能彼此独立地扩展,出现故障后不影响其他服务。
一旦作好准备,就使用自动扩展。
不做重复性工作,使用托管服务,而不是自行编写服务,除非绝对有必要这么做。
如果有必要的话,改用NoSQL。
补充资料:
2007年的亚马逊架构:http://highscalability.com/blog/2007/9/18/amazon-architecture.html
云头条编译|未经授权谢绝转载
欢迎加入,群主微信:aclood